/* ------------------------------------------
*   Copyright (c) [2022] [R.H.Shen]
*   [SC4AC] is licensed under Mulan PSL v2.
*   You can use this software according to the terms and conditions of the Mulan
*   PSL v2.
*   You may obtain a copy of Mulan PSL v2 at:
*              http://license.coscl.org.cn/MulanPSL2
*   THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
*	KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
*	NON-INFRINGEMENT, *	MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*   See the Mulan PSL v2 for more details.
---------------------------------------------- */

#include "commom.h"

#include <stdalign.h>

#include "Serial.h"

// 文件接口
#include <fstream>

using namespace std;

// ========================

/// ======= 数据转化 ===============
void FloatToByte(float value, unsigned char *bytes, int size) {  // 小端机器
  memset(bytes, 0,
         sizeof(unsigned char) *
             size);  // void *s, int ch. size_t n
                     // 把s中当前位置后面的n个字节用ch替换并返回s.
  unsigned char *ptr = (unsigned char *)&value;
  bytes[0] = *ptr;
  bytes[1] = *(ptr + 1);
  bytes[2] = *(ptr + 2);
  bytes[3] = *(ptr + 3);
  // cout << hex<<bytes;
}

/// =============== 发送数据帧函数==========
/// 发送数据帧 参数: serial s 串口类,  int msg_type 消息类型,
/// float msg[] 消息数据, int msg_l消息长度
void uart_send(Serial &s, int msg_type, float msg[], int msg_l) {
  uint8_t msg_length = msg_l * sizeof(float);  // 有效数据字节数
  uint8_t buf_length = msg_length + 6;         // 发送缓冲区字节数

  uint8_t sumA = 0;
  uint8_t sumB = 0;

  unsigned char tx_buf[60];                       // 'A'(0X41) 'C'(0X43)
  memset(tx_buf, 0, sizeof(unsigned char) * 20);  // void *s, int ch. size_t n

  // cout << msg<<endl;

  tx_buf[0] = 0x41;               //'A'
  tx_buf[1] = 0x43;               //'C'
  tx_buf[2] = uint8_t(msg_type);  // 发送msg_type  <----- buf[2]
  sumA = sumA + tx_buf[2];
  sumB = sumB + sumA;
  tx_buf[3] = msg_length;  // 发送有效数据字节长度 msg-lenth  <------buf[3]
  sumA = sumA + tx_buf[3];
  sumB = sumB + sumA;
  int index = 4;

  // 往发送缓冲区存有效数据
  for (int i = 0; i < msg_l; i++) {
    unsigned char bytes[4];
    memset(bytes, 0, sizeof(unsigned char) * 4);  // void *s, int ch. size_t n
    FloatToByte(msg[i], bytes, 4);
    for (int j = 0; j < 4; j++) {
      // 每个浮点型4个char填充
      // cout << hex << bytes[j] << endl;
      tx_buf[index] = bytes[j];
      sumA = sumA + tx_buf[index];
      sumB = sumB + sumA;
      index++;
    }
  }

  tx_buf[index] = sumA;
  index++;
  tx_buf[index] = sumB;
  index++;
  tx_buf[index] = '\0';
  const char *tx;
  char tmp;
  for (int i = 0; i < buf_length; i++) {
    tmp = char(tx_buf[i]);
    tx = &tmp;
    s.write(tx, 1);
  }
}
//=================发送数据帧函数 结束=============

//=================接收数据帧函数 开始=============
/// 接收缓冲区的数据
/// 参数: Serial &s(引用),  int &msg_type, float msg[], int &msg_l
/// 返回值: msg_l
bool uart_receive(Serial &s, int &msg_type, float msg[], int &msg_l) {
  // unsigned 和 signed 类型互换  : 统一用unsigned,
  // 在需要的地方用(char*)强制类型转化
  // 简单二次开发协议解析
  msg_type = 255;  // 默认错误类型
  msg_l = 0;
  memset(msg, 0, sizeof(float) * 10);  // void *s, int ch. size_t n

  /*状态机变量   静态局部变量*/
  static uint8_t rc_step1 = 0;  // 0：接收包头'A' 'C'
                                // 1：接收1字节消息类别
                                // 2：接收1字节消息长度
                                // 3：接收数据包内容
                                // 4：接收2字节校验
  static uint8_t rc_step2 = 0;
#define MAX_RX_SDI_PACKET_SIZE 4 * 10  // 有效数据接收缓冲区大小 10个浮点类型
  static uint8_t msg_length;  // 有效数据字节长度
  alignas(4) static uint8_t msg_pack[MAX_RX_SDI_PACKET_SIZE];  // 有效数据区
  static uint8_t sumA;
  static uint8_t sumB;

#define reset_SDI_RC (rc_step1 = rc_step2 = 0)
  /*状态机变量*/

  uint8_t rc_buf[60];
  uint8_t length = s.read((char *)rc_buf, 60, 100);

  for (uint8_t i = 0; i < length; ++i) {
    uint8_t r_data = rc_buf[i];
    switch (rc_step1) {
      case 0:
        // 接收包头'A''C'
        if (rc_step2 == 0) {
          if (r_data == 'A') rc_step2 = 1;
        } else {
          if (r_data == 'C') {
            rc_step1 = 1;
            rc_step2 = 0;
            sumA = sumB = 0;
          } else
            rc_step2 = 0;
        }
        break;

      case 1:
        // 接收消息类别
        msg_type = int(r_data);
        sumA += r_data;
        sumB += sumA;
        rc_step1 = 2;
        rc_step2 = 0;

        break;

      case 2:
        // 接收消息长度
        if (r_data > MAX_SDI_PACKET_SIZE) {
          reset_SDI_RC;
          break;
        }
        msg_length = r_data;
        sumA += r_data;
        sumB += sumA;
        if (msg_length == 0)
          rc_step1 = 4;
        else
          rc_step1 = 3;
        rc_step2 = 0;
        break;

      case 3:
        // 接收数据包
        msg_pack[rc_step2] = r_data;
        sumA += r_data;
        sumB += sumA;
        ++rc_step2;
        if (rc_step2 >= msg_length) {
          rc_step1 = 4;
          rc_step2 = 0;
        }
        break;

      case 4:
        // 接收校验位
        if (rc_step2 == 0) {
          if (sumA != r_data) {
            reset_SDI_RC;
            break;
          }
          rc_step2 = 1;
        } else {
          if (sumB == r_data) {
            msg_l = int(msg_length >> 2);  // 右移两位, 获得float数据个数
            msg_type = int(msg_type);
            msg[0] = *(float *)&msg_pack[0];
            msg[1] = *(float *)&msg_pack[4];
            msg[2] = *(float *)&msg_pack[8];
            msg[3] = *(float *)&msg_pack[12];
            msg[4] = *(float *)&msg_pack[16];
            msg[5] = *(float *)&msg_pack[20];
            msg[6] = *(float *)&msg_pack[24];
            msg[7] = *(float *)&msg_pack[28];
            msg[8] = *(float *)&msg_pack[32];
            reset_SDI_RC;
            return true;
          }
          break;
        }
    }
  }
  return false;
}

/// ==================接收数据帧程序 结束==================